package com.vegetable.modules.service.stock.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.vegetable.modules.entity.inbound.OrderCost;
import com.vegetable.modules.entity.stock.Stock;
import com.vegetable.modules.entity.stock.po.StockCostAddPO;
import com.vegetable.modules.entity.stock.po.StockCostChangeQueryPO;
import com.vegetable.modules.entity.stock.to.StockCostChangeDTO;
import com.vegetable.modules.mapper.stock.StockCostChangeMapper;
import com.vegetable.modules.mapper.stock.StockMapper;
import com.vegetable.modules.service.inbound.IOrderCostService;
import com.vegetable.modules.service.stock.IStockCostChangeService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.dao.OptimisticLockingFailureException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;

/**
 * <p>
 * 库存表 服务类
 * </p>
 *
 * @author wangruijie
 * @since 2024-03-21
 */
@Slf4j
@Service
@AllArgsConstructor
public class StockCostChangeServiceImpl extends ServiceImpl<StockCostChangeMapper, StockCostChangeDTO> implements IStockCostChangeService {

    @Resource
    private StockCostChangeMapper stockCostChangeMapper;
    @Resource
    private StockMapper stockMapper;
    
    @Lazy
    @Resource
    private IOrderCostService orderCostService;

    @Override
    public IPage<StockCostChangeDTO> stockCostChange(StockCostChangeQueryPO po) {
        Page<StockCostChangeDTO> page = new Page<>(po.getPage(), po.getLIMIT());
        QueryWrapper<StockCostChangeDTO> queryWrapper = new QueryWrapper<>();
        queryWrapper.like(ObjectUtil.isNotNull(po.getCommodityNameLike()), "commodity_name", po.getCommodityNameLike());
        queryWrapper.eq(ObjectUtil.isNotNull(po.getStockId()), "stock_id", po.getStockId());
        queryWrapper.gt("before_cost", 0);
        queryWrapper.orderByDesc("stock_id");
        IPage<StockCostChangeDTO> result = stockCostChangeMapper.selectPage(page, queryWrapper);
        List<StockCostChangeDTO> records = result.getRecords();
        if(CollectionUtil.isNotEmpty(records)){
            for(StockCostChangeDTO dto : records){
                JSONArray ja = JSONArray.parseArray(dto.getNowCostDetail());
                if(CollectionUtil.isEmpty(ja)){
                    continue;
                }
                List<Map<String, String>> changeCostDetailList = new ArrayList<>();
                for(int i = 0; i < ja.size(); i++){
                    JSONObject jj = ja.getJSONObject(i);
                    Set<String> keys = jj.keySet();
                    for(String key : keys){
                        Map<String, String> detail = new HashMap<>();
                        detail.put("costClauseName", key);
                        detail.put("money", jj.getString(key));
                        changeCostDetailList.add(detail);
                    }
                }
                dto.setChangeCostDetailList(changeCostDetailList);
            }
        }
        return result;
    }
    @Override
    public Integer add(StockCostChangeDTO po) {
        if(CollectionUtil.isNotEmpty(po.getChangeCostDetailList())){
            po.setNowCostDetail(JSONArray.toJSONString(po.getChangeCostDetailList()));
        }
        po.setCreateTime(new Date());
        try {
            this.baseMapper.insert(po);
        }catch (Exception e){
            e.printStackTrace();
        }
        return 1;
    }
    @Transactional
    @Override
    public void StockCostAddPO(StockCostAddPO po) throws Exception {
        // 库存id集
        List<Stock> stockList = getStocks(po.getStockIds());
        // 分摊总重量
        Double totalWeight = stockList.stream().mapToDouble(flow -> flow.getInitWeight().doubleValue()).sum();
        // 新增的库内管理费用
        List<OrderCost> orderCostList = po.getOrderCosts();
        for(OrderCost oc : orderCostList){
            BigDecimal money =  oc.getMoney();
            for(Stock stock : stockList){
                // 库存重量占此次总货品重量的比重
                BigDecimal stockMoney = updateStock(totalWeight, money, stock);
                saveCostChange(oc, stock, stockMoney);
            }
        }
    }

    private void saveCostChange(OrderCost oc, Stock stock, BigDecimal stockMoney) {
        StockCostChangeDTO dto = new StockCostChangeDTO();
        BeanUtils.copyProperties(stock, dto);
        dto.setBeforeCost(stock.getCostWeight());
        dto.setNowCost(stock.getCostWeight());
        List<Map<String, String>> detailList = new ArrayList<>();
        Map<String, String> detail = new HashMap<>();
        detail.put(oc.getCostClauseName(), stockMoney.toEngineeringString());
        detailList.add(detail);
        dto.setChangeCostDetailList(detailList);
        dto.setStockId(stock.getId());
        // 增加库存成本变化记录
        add(dto);
    }

    @Override
    public void revokeCostChange(StockCostAddPO po) throws Exception {
        List<Stock> stockList = getStocks(po.getStockIds());
        // 分摊总重量
        Double totalWeight = stockList.stream().mapToDouble(flow -> flow.getWeight().doubleValue()).sum();
        // 新增的库内管理费用
        List<OrderCost> orderCostList = po.getOrderCosts();
        for(OrderCost oc : orderCostList){
            BigDecimal money =  oc.getMoney();
            for(Stock stock : stockList){
                updateStock(totalWeight, money, stock);
            }
        }
        this.baseMapper.deleteBatchIds(po.getIds());
    }

    private BigDecimal updateStock(Double totalWeight, BigDecimal money, Stock stock) {
        // 库存重量占此次总货品重量的比重
        Double rate = stock.getInitWeight().doubleValue() / totalWeight;
        // 该库存管理费用的总额
        BigDecimal stockMoney = NumberUtil.mul(money, rate);
        // 该库存管理费用的总额 按重量分摊
        BigDecimal stockMoneyUnit = NumberUtil.div(stockMoney, stock.getInitWeight());
        stock.setWmsUnitPrice(NumberUtil.add(stock.getWmsUnitPrice(), stockMoneyUnit));
        stock.setCost(NumberUtil.add(stock.getCost(), stockMoney));
        stock.setCostWeight(NumberUtil.add(stock.getCostWeight(), stockMoneyUnit));
        // 更新库存
        int res = stockMapper.updateById(stock);
        if(res != 1){
            throw new OptimisticLockingFailureException("库存跟新失败，请刷新页面重试");
        }
        return stockMoney;
    }

    private List<Stock> getStocks(List<Long> stockIds) throws Exception {
        // 库存id集
        List<Stock> stockList = stockMapper.selectBatchIds(stockIds);
//        Optional<Stock> emptyData = stockList.stream().filter(flow -> flow.getNumber() == 0 && NumberUtil.equals(flow.getWeight(), BigDecimal.ZERO)).findAny();
//        if(emptyData.isPresent()){
//            Stock stock = emptyData.get();
//            throw new Exception(stock.getCommodityName() + "(" + stock.getSpecsName()+")库存为空，不能在添加库内管理费用");
//        }
        return stockList;
    }
}
